package com.alibaba.nacos.example.spring.cloud.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.nacos.example.spring.cloud.config.OssConfig;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CompleteMultipartUploadRequest;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.InitiateMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadResult;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PartETag;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.UploadPartRequest;
import com.aliyun.oss.model.UploadPartResult;

/**
 * @author Administrator
 */
@Component
public class OssUtil {
	private static final Logger log = LoggerFactory.getLogger(OssUtil.class);
	private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
	/*private static String OssConfig.ALIYUN_END_POINT = OssConfig.ALIYUN_END_POINT;
	private static String accessKeyId = OssConfig.ALIYUN_ACCESS_KEY_ID;
	private static String accessKeySecret = OssConfig.ALIYUN_ACCESS_KEY_SECRET;
	private static String OssConfig.ALIYUN_BUCKET_NAME = OssConfig.ALIYUN_BUCKET_NAME;
	private static String fileHost = OssConfig.ALIYUN_FILE_HOST;*/
	private static String dateStr = format.format(new Date());
	
	/**
	 * 总路径 return 路径
	 */
	public static String basePath(String fileUrl) {
		return "https://" + OssConfig.ALIYUN_BUCKET_NAME + "." + OssConfig.ALIYUN_END_POINT + "/"+fileUrl;
	}

	/**
	 * @Date 上传文件没后缀
	 * @param file
	 * @return
	 */
	public static String upload(File file) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		try {
			// 容器不存在,就创建
			if (!ossClient.doesBucketExist(OssConfig.ALIYUN_BUCKET_NAME)) {
				ossClient.createBucket(OssConfig.ALIYUN_BUCKET_NAME);
				CreateBucketRequest createBucketRequest = new CreateBucketRequest(OssConfig.ALIYUN_BUCKET_NAME);
				createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
				ossClient.createBucket(createBucketRequest);
			}
			// 创建文件路径
			String fileUrl = OssConfig.ALIYUN_FILE_HOST + "/" + (dateStr + "/" + AESUtil.generateCode(12));
			// 上传文件
			PutObjectResult result = ossClient.putObject(new PutObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, fileUrl, file));
			// 设置权限 这里是公开读
			ossClient.setBucketAcl(OssConfig.ALIYUN_BUCKET_NAME, CannedAccessControlList.PublicRead);
			if (null != result) {
				System.out.println("文件上传成功后地址：" + fileUrl);
				System.out.println("文件上传成功后浏览器访问路径：" + basePath(fileUrl));
				log.error("文件上传成功后地址：" +  fileUrl);
				log.error("文件上传成功后浏览器访问路径：" +  basePath(fileUrl));
				return fileUrl;
			}
		} catch (OSSException oe) {
			log.error(oe.getMessage());
		} catch (ClientException ce) {
			log.error(ce.getMessage());
		} finally {
			//关闭输入流
			ossClient.shutdown();
		}
		return null;
	}
	/**
	 * @Date 上传文件有后缀
	 * @param file
	 * @return
	 */
	public static String uploadSuffix(File file) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		try {
			// 容器不存在,就创建
			if (!ossClient.doesBucketExist(OssConfig.ALIYUN_BUCKET_NAME)) {
				ossClient.createBucket(OssConfig.ALIYUN_BUCKET_NAME);
				CreateBucketRequest createBucketRequest = new CreateBucketRequest(OssConfig.ALIYUN_BUCKET_NAME);
				createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
				ossClient.createBucket(createBucketRequest);
			}
			// 创建文件路径
			String fileUrl = OssConfig.ALIYUN_FILE_HOST + "/" + (dateStr + "/" + AESUtil.generateCode(12)+file.getName());
			// 上传文件
			PutObjectResult result = ossClient.putObject(new PutObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, fileUrl, file));
			// 设置权限 这里是公开读
			ossClient.setBucketAcl(OssConfig.ALIYUN_BUCKET_NAME, CannedAccessControlList.PublicRead);
			if (null != result) {
				System.out.println("文件上传成功后地址：" + fileUrl);
				System.out.println("文件上传成功后浏览器访问路径：" + basePath(fileUrl));
				log.error("文件上传成功后地址：" +  fileUrl);
				log.error("文件上传成功后浏览器访问路径：" +  basePath(fileUrl));
				return  fileUrl;
			}
		} catch (OSSException oe) {
			log.error(oe.getMessage());
		} catch (ClientException ce) {
			log.error(ce.getMessage());
		} finally {
			//关闭输入流
			ossClient.shutdown();
		}
		return null;
	}
	/**
	 * @Date 分片上传
	 * @param file
	 * @return
	 * @throws FileNotFoundException 
	 */
	public static String UploadFragmentation(String objectName) throws Exception {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		/* 步骤1：初始化一个分片上传事件。
		*/
		InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);
		// 返回uploadId，它是分片上传事件的唯一标识，您可以根据这个ID来发起相关的操作，如取消分片上传、查询分片上传等。
		String uploadId = result.getUploadId();
		/* 步骤2：上传分片。
		*/
		// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
		List<PartETag> partETags =  new ArrayList<PartETag>();
		// 计算文件有多少个分片。
		final long partSize = 1 * 1024 * 1024L;   // 1MB
		final File sampleFile = new File(objectName);
		long fileLength = sampleFile.length();
		int partCount = (int) (fileLength / partSize);
		if (fileLength % partSize != 0) {
		    partCount++;
		 }
		// 遍历分片上传。
		for (int i = 0; i < partCount; i++) {
		    long startPos = i * partSize;
		    long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
		    InputStream instream = new FileInputStream(sampleFile);
		    // 跳过已经上传的分片。
		    instream.skip(startPos);
		    UploadPartRequest uploadPartRequest = new UploadPartRequest();
		    uploadPartRequest.setBucketName(OssConfig.ALIYUN_BUCKET_NAME);
		    uploadPartRequest.setKey(objectName);
		    uploadPartRequest.setUploadId(uploadId);
		    uploadPartRequest.setInputStream(instream);
		    // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100KB。
		    uploadPartRequest.setPartSize(curPartSize);
		    // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出这个范围，OSS将返回InvalidArgument的错误码。
		    uploadPartRequest.setPartNumber( i + 1);
			// 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
		    UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
			// 每次上传分片之后，OSS的返回结果会包含一个PartETag。PartETag将被保存到partETags中。
		    partETags.add(uploadPartResult.getPartETag());
		}

		/* 步骤3：完成分片上传。
		*/
		// 排序。partETags必须按分片号升序排列。
		Collections.sort(partETags, new Comparator<PartETag>() {
		    public int compare(PartETag p1, PartETag p2) {
		        return p1.getPartNumber() - p2.getPartNumber();
		    }
		});
		// 在执行该操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
		CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName, uploadId, partETags);
		ossClient.completeMultipartUpload(completeMultipartUploadRequest);
		// 关闭OSSClient。
		ossClient.shutdown();
		return uploadId;
	}
	/**
	 * @Date 删除Object
	 * @param fileKey
	 * @return
	 */
	public static String deleteFile(String fileKey) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		try {
			if (!ossClient.doesBucketExist(OssConfig.ALIYUN_BUCKET_NAME)) {
				log.info("您的Bucket不存在");
				return "您的Bucket不存在";
			} else {
				log.info("开始删除Object");
				ossClient.deleteObject(OssConfig.ALIYUN_BUCKET_NAME, fileKey);
				log.info("删除成功：" + fileKey);
				return "删除成功：" + fileKey;
			}
		} catch (Exception ex) {
			log.info("删除Object失败", ex);
			return "删除Object失败";
		}
	}

	/**
	 * @Date 查询文件名列表
	 * @param OssConfig.ALIYUN_BUCKET_NAME
	 * @return
	 */
	public static List<String> getObjectList(String bucketName) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		List<String> listRe = new ArrayList<>();
		try {
			log.info("查询文件名列表");
			ListObjectsRequest listObjectsRequest = new ListObjectsRequest(OssConfig.ALIYUN_BUCKET_NAME);
			// 列出OSS目录下当天所有文件
			listObjectsRequest.setPrefix("aliyun/" + format.format(new Date()) + "/");
			ObjectListing list = ossClient.listObjects(listObjectsRequest);
			for (OSSObjectSummary objectSummary : list.getObjectSummaries()) {
				listRe.add(objectSummary.getKey());
			}
			return listRe;
		} catch (Exception ex) {
			log.info("查询列表失败", ex);
			return new ArrayList<>();
		}
	}

	/**
	 * @Date 通过文件名下载文件
	 * @param objectName    要下载的文件名
	 * @param localFileName 本地要创建的文件名
	 */
	public static String downloadFile(String objectName, String localFileName) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
		ossClient.getObject(new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName), new File(localFileName));
		// 关闭OSSClient
		//ossClient.shutdown();
		return "下载成功";
	}

	/**
	 * @Date 图片样式处理
	 * @param objectName
	 * @return
	 */
	public static String image(String objectName) {
		OSSClient ossClient = new OSSClient(OssConfig.ALIYUN_END_POINT, OssConfig.ALIYUN_ACCESS_KEY_ID, OssConfig.ALIYUN_ACCESS_KEY_SECRET);
		// 设置图片处理样式。
		String style = "image/resize,m_fixed,w_100,h_100/rotate,90";
		// 指定过期时间为10分钟。
		Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10);
		GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName, HttpMethod.GET);
		req.setExpiration(expiration);
		req.setProcess(style);
		URL signedUrl = ossClient.generatePresignedUrl(req);
		System.out.println(signedUrl);
		// 缩放
		GetObjectRequest request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-resize.jpg"));
		// 裁剪
		style = "image/crop,w_100,h_100,x_100,y_100,r_1";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-crop.jpg"));
		// 旋转
		style = "image/rotate,90";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-rotate.jpg"));
		// 锐化
		style = "image/sharpen,100";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-sharpen.jpg"));
		// 水印
		style = "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-watermark.jpg"));
		// 格式转换
		style = "image/format,png";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-format.png"));
		// 获取图片信息
		style = "image/info";
		request = new GetObjectRequest(OssConfig.ALIYUN_BUCKET_NAME, objectName);
		request.setProcess(style);
		ossClient.getObject(request, new File("example-info.txt"));
		// 关闭OSSClient。
		ossClient.shutdown();
		return style;
	}
}